package awk.productconsumer;

import awk.thread.ThreadPoolUtils;

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*
 * 生产者消费者案例：
 */
public class ProductConsumerForCondition {

    public static void main(String[] args) {
        ThreadPoolExecutor pool = ThreadPoolUtils.getPool();
        Clerk clerk = new Clerk();
        pool.execute(() -> {
            for (int i = 0; i < 20; i++) {
                clerk.products();
            }
        });
        pool.execute(() -> {
            for (int i = 0; i < 200; i++) {
                clerk.sale();
            }
        });
    }

    /**
     * 两种方式：
     * 1.生产一个,卖出一个；卖出一个，生产一个
     * 2.加上if判断,库存不足通知生产,通知停止销售; 库存满了,停止生产,同时抓紧销售
     */
    static class Clerk {
        private volatile int goods = 0;
        private Lock lock = new ReentrantLock();
        private Condition product = lock.newCondition();
        private Condition consumer = lock.newCondition();

        public void products() {
            lock.lock();
            try {
                // 为了避免虚假唤醒，应该总是使用在循环中。
          /*      if (goods > 3) {
                    System.out.println("产品已满,还有库存" + goods);
                    product.await();
                    consumer.signal();
                }*/
                goods++;
                System.out.println("生产一个,还有库存" + goods);
                product.await();
                consumer.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public void sale() {
            lock.lock();
            try {
            /*    if (goods <= 1) {
                    System.out.println("缺货！");
                    product.signal();//signal()会唤醒某个等待线程；
                    consumer.await(); //await()会释放当前锁，进入等待状态；
                }*/
                goods--;
                System.out.println("卖出一个,还有库存" + goods);
                product.signal();//signal()会唤醒某个等待线程；
                consumer.await(); //await()会释放当前锁，进入等待状态；
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}
